﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace frag_boardgame
{

    /// <summary>
    /// This class all the data in the game. It contains absolutely no logic.
    /// </summary>
    [DataContract]
    public class GameData
    {
        [DataMember]
        private Board board;

        [DataMember]
        public int current_player;

        [DataMember]
        private List<Player> players;

        /// <summary>
        /// Constructor: it probalbly will get paramters such number of players
        /// and other unique things regarding the game
        /// </summary>
        public GameData(Configuraion conf)
        {
            // Create a new Board:
            //board = new Board(conf.Rows,conf.Cols);
            board = conf.CreateBoard();
            players = new List<Player>();
            int NumOfPlayers = 0;
            foreach (PlayerConfiguration playerConf in conf.PlayerConfigurations)
            {
                NumOfPlayers++;
                Player pl = new Player(playerConf,NumOfPlayers);
                Square sqr_player = board.GetSquare(playerConf.StartingPosition.row, playerConf.StartingPosition.col);
                sqr_player.player = pl;
                players.Add(pl);
            }

            current_player = 0;

        }

        /// <summary>
        /// This method will be used for the test units..  I'm not sure that it is needed at all..
        /// we need to think about it.
        /// </summary>
        /// <returns></returns>
        public Board Board
        {
            get { return board; }
        }

        public Player CurrentPlayer
        {
            get 
            {
                if (GetPlayersList().Count == 1)
                    current_player = 0;
                if (GetPlayersList().Count <= current_player)
                    current_player = 0;
                return GetPlayersList().ElementAt(current_player);
            }
        }

        /// <summary>
        /// This method Generates a list with the players list
        /// </summary>
        /// <returns></returns>
        public ICollection<Player> GetPlayersList()
        {
            List<Player> playersList = new List<Player>();

            foreach (Player player in players)
            {
                if (!player.isDead())
                {
                    playersList.Add(player);
                }
            }
           return playersList;
            
        }

        
        public Player GetPlayer(int id)
        {
            foreach (Player player in players)
            {
                if (player.ID == id)
                    return player;
            }
            return null;
        }


        #region Save and Load

        public void Save(System.IO.Stream stream)
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(GameData));
            ser.WriteObject(stream, this);
        }

        public static GameData Load(System.IO.Stream stream)
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(GameData));
            GameData game = (GameData)ser.ReadObject(stream);

            return game;
        }

        #endregion


        // override object.Equals
        public override bool Equals(object obj)
        {
            GameData g = obj as GameData;
            if (g == null) return false;


            bool playersAreEqual = true;
            for (int i = 0; i < players.Count; i++ )
            {
                playersAreEqual = playersAreEqual && Equals(players.ElementAt(i), g.players.ElementAt(i));
            }
            return Equals(g.board, board) &&
                playersAreEqual &&
                Equals(g.current_player, current_player);
        }

        // override object.GetHashCode
        public override int GetHashCode()
        {
            int hash = board.GetHashCode();
            hash = hash ^ current_player.GetHashCode();
            if (players != null)
                foreach (Player player in players)
                {
                    hash = hash ^ player.GetHashCode();
                }

            return hash;
        }


        public GameData Clone()
        {
            // Serialize and deserialize the object
            using (MemoryStream ms = new MemoryStream()) {
                Save(ms);
                ms.Seek(0, SeekOrigin.Begin);
                return GameData.Load(ms);
            }
        }
    }
}
